﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ITAP.ShprossesBuilder.Modelling;
using ITAP.ShprossesBuilder.Modelling.Components;
using ITAP.ShprossesBuilder.Calculations;
using ITAP.ShprossesBuilder.Manipulation;
using ITAP.ShprossesBuilder.Manipulation.Tolerance;
using ITAP.ShprossesBuilder.Operations;
using ITAP.ShprossesBuilder.Manipulation.PopupMenu;
using ITAP.ShprossesBuilder.Properties;
using ITAP.Core.Modelling;
using ITAP.Core.Calculations;

namespace ITAP.ShprossesBuilder
{
    public partial class MainControl : UserControl
    {
      //  private ToleranceManager toleranceManager;

        public ToleranceManager ToleranceManager
        {
            get { return modelControl.ToleranceManager; }
        }

        public void RegisterManipulatorVisitor(VisitorInfo visitorInfo)
        {
            this.Manipulator.VisitorsInfo.Add(visitorInfo);
        }

        private MouseButtons currentPressedButton = MouseButtons.None;
        
        private MouseManipulatorManager mouseManager;

        public MouseManipulatorManager MouseManager
        {
            get { return mouseManager; }
            set { mouseManager = value; }
        }

        //private List<IModelControlCommand> mouseDownAutoCommands;

        //public List<IModelControlCommand> MouseDownAutoCommands
        //{
        //    get { return mouseDownAutoCommands; }
        //    set { mouseDownAutoCommands = value; }
        //}
        //private List<IModelControlCommand> mouseMoveAutoCommands;

        //public List<IModelControlCommand> MouseMoveAutoCommands
        //{
        //    get { return mouseMoveAutoCommands; }
        //    set { mouseMoveAutoCommands = value; }
        //}
        //private List<IModelControlCommand> mouseUpAutoCommands;

        //public List<IModelControlCommand> MouseUpAutoCommands
        //{
        //    get { return mouseUpAutoCommands; }
        //    set { mouseUpAutoCommands = value; }
        //}

        public ModelCoordinateConverter CoordinateConverter
        {
            get
            {
                return modelControl.CoordinateConverter;
            }
        }

        private IModelControlCommand currentEditorCommand;

        public IModelControlCommand CurrentEditorCommand
        {
            get { return currentEditorCommand; }
            set 
            { 
                currentEditorCommand = value;
                if (value != null && currentEditorCommand.ExecuteImmediately)
                {
                    Manipulator.StartExecute(currentEditorCommand);
                    Manipulator.Execute(currentEditorCommand);
                    Manipulator.EndExecute(currentEditorCommand);
                }
            }
        }
       // private ModelManipulator manipulator;

        public ModelManipulator Manipulator
        {
            get { return modelControl.Manipulator; }
        }

        //private Point mouseDownPoint;
        //private Point offset;

        public bool UseAutoScale
        {
            get
            {
                return modelControl.UseAutoScale;
            }
            set
            {
                modelControl.UseAutoScale = value;
                if (value == true)
                    if (modelControl.ModelContainer != null)
                        modelControl.Camera = new ModelPoint(modelControl.ModelContainer.BoundingBox.Width / 2, modelControl.ModelContainer.BoundingBox.Height / 2);
            }
        }

        public ModelContainer ModelContainer
        {
            get
            {
                return modelControl.ModelContainer;
            }
            set
            {
                modelControl.ModelContainer = value;
                if (modelControl.ModelContainer != null)
                    RecalculateScrollBars();
            }
        }

        public ModelPoint CenterOfView
        {
            get
            {
                return modelControl.Camera;
            }
            set
            {
                if (value != null)
                    modelControl.Camera = (ModelPoint)value.Clone();
            }
        }

        public ModelPoint ModelContainerCenterPoint
        {
            get
            {
                RectangleF bbox = modelControl.ModelContainer.BoundingBox;
                return new ModelPoint(bbox.Width / 2, bbox.Height / 2);
            }
        }

        public MainControl()
        {
            ModelCalculations.InitializeCaches();

            InitializeComponent();
            modelControl.MouseWheel += new MouseEventHandler(modelControl_MouseWheel);
            modelControl.KeyDown += new KeyEventHandler(modelControl_KeyDown);
            modelControl.KeyUp += new KeyEventHandler(modelControl_KeyUp);
            mouseManager = new MouseManipulatorManager(this, Manipulator);
            this.RegisterManipulatorVisitor(new VisitorInfo(modelControl.ToleranceManager, 
                new Type[] { typeof(CommandEditorAddComponentToModel), 
                             typeof(CommandPropertyGridValueChanged), 
                             typeof(CommandMoveComponent), 
                             typeof(CommandEditorBreakComponent),  
                             typeof(CommandRotateComponent),
                typeof(CommandOperation),
                typeof(CommandCreateShprossesOnShprossConnector), 
                typeof(CommandEditorChangeShprossLength) } ));        
            
        }

        public ProfilesProviderDelegate ProfileProvider
        {
            get { return this.modelControl.ProfileProvider; }            
        }

        /// <summary>
        /// Здесь инициализируем правила обработки команд мышью и просто команд. Например, здесь создаётся 
        /// контейнер моделей ModelContainer с помощью соответствующей команды. Для корректной работы визиторов, 
        /// назначенных модели, необходимо зарегистрировать их в манипуляторе ДО вызова этого метода. 
        /// Например, при создании 
        /// контейнера моделей надо создать соответствующий контрол TreeView на некоторой форме, отражающий 
        /// структуру моделей. Необходимо зарегистрировать его как визитор ДО вызова этого метода, потому что 
        /// этот метод и создаёт с помощью команды контейнер моделей, и манипулятор должен будет оповестить уже существующий визитор
        /// TreeView, зарегистрированный для этой команды.
        /// </summary>
        public void Initialize(CreateModelContainerDelegate createModelContainerDelegate, ProfilesProviderDelegate profileProvider)
        {
            this.modelControl.SetProfileProvider(profileProvider);
            // Ни одна кнопка мыши и клавиатуры не нажата. 
            // Очерёдность запуска команд определяется последовательностью регистрации.
            //
            // При любом положении мыши надо работать с той моделью, над которой курсор и над которой произошло событие MouseUp, 
            // поэтому сразу выделяем нужную модель.
        //    mouseManager.RegisterCommand(new CommandEditorSelectModelCell(modelControl, ""), new MouseManagerEvent(MouseButtons.None, Keys.None));

            // Выделение зарегистрированных элементов модели.
            mouseManager.RegisterCommand(new CommandSelectComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(SnapOnCap), typeof(Shpross), typeof(ModelContainer) }), new MouseManagerEvent(MouseButtons.Left, Keys.None));

            // Нажата левая кнопка мыши.
            //
            mouseManager.RegisterCommand(new CommandEditorNavigation(modelControl, new Type[] { typeof(ModelContainer), typeof(Spacer), typeof(SpacerElement), typeof(Model), typeof(ModelCell) }, ""), new MouseManagerEvent(MouseButtons.Left, Keys.None));
            mouseManager.RegisterCommand(new CommandEditorNavigation(modelControl, new Type[] { typeof(ModelContainer), typeof(Spacer), typeof(SpacerElement), typeof(Model), typeof(ModelCell) }, ""), new MouseManagerEvent(MouseButtons.Left, Keys.Q));
            mouseManager.RegisterCommand(new CommandEditorNavigation(modelControl, new Type[] { typeof(ModelContainer), typeof(Spacer), typeof(SpacerElement), typeof(Model), typeof(ModelCell) }, ""), new MouseManagerEvent(MouseButtons.Left, Keys.W));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(Shpross) }, ""), new MouseManagerEvent(MouseButtons.Left, Keys.None));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(Shpross) }, ""), new MouseManagerEvent(MouseButtons.Left,  Keys.Q));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(Shpross) }, ""), new MouseManagerEvent(MouseButtons.Left, Keys.W));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(Shpross) }, ""), new MouseManagerEvent(MouseButtons.Left, (Keys.ControlKey | Keys.Control)));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector) }, ""), new MouseManagerEvent(MouseButtons.Left, (Keys.Menu | Keys.Alt)));
            mouseManager.RegisterCommand(new CommandMoveComponent(modelControl, new Type[] { typeof(ShprossConnector) }, ""), new MouseManagerEvent(MouseButtons.Right, (Keys.Menu | Keys.Alt)));

            mouseManager.RegisterCommand(new CommandEditorChangeShprossLength(modelControl), new MouseManagerEvent(MouseButtons.Left, Keys.L));


            mouseManager.RegisterCommand(new CommandEditorBreakComponent(modelControl, new Type[] { typeof(Shpross) }), new MouseManagerEvent(MouseButtons.Middle, Keys.None));

            // Если щёлкнули по элементу модели, которая не выделена - выделить это модель.
            mouseManager.RegisterCommand(new CommandEditorSelectModelCell(modelControl, ""), new MouseManagerEvent(MouseButtons.Left, Keys.None));


            // Нажата левая кнопка мыши с клавишей Shift.
            //
            // Если щёлкнули с зажатым Shift - выделенные до этого элементы останутся выделенными (логика для этого внутри самой команды).
            mouseManager.RegisterCommand(new CommandSelectComponent(modelControl, new Type[] { typeof(ShprossConnector), typeof(SnapOnCap), typeof(Shpross), typeof(ModelContainer) }), new MouseManagerEvent(MouseButtons.Left, (Keys.ShiftKey | Keys.Shift)));            


            PopupMenuProvider popupProvider = this.CreatePopupMenus();
            mouseManager.RegisterCommand(new CommandPopupMenu(modelControl, new Type[] { typeof(Shpross), typeof(ShprossConnector), typeof(SnapOnCap) }, popupProvider), new MouseManagerEvent(MouseButtons.Right, Keys.None));



            OperationRemoveComponent operationRemoveComponent = new OperationRemoveComponent();
            IModelComponentCommand deleteComponentsCommand = new CommandOperation(modelControl, operationRemoveComponent);
            mouseManager.RegisterCommand(deleteComponentsCommand, new MouseManagerEvent(MouseButtons.None, Keys.Delete));


            this.InitializeHotKeys();


            ICommand createModelContainer = new CommandCreateModelContainer(this.modelControl, createModelContainerDelegate);
            Manipulator.StartExecute(createModelContainer);
            Manipulator.Execute(createModelContainer);
            Manipulator.EndExecute(createModelContainer);

            this.ModelControl.UpdateModel();
        }

        private void InitializeHotKeys()
        {
            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationDisperseShprossConnectors()),
                new MouseManagerEvent(MouseButtons.None, (Keys.D | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationCreateShprossesOnShprossConnector()),
                new MouseManagerEvent(MouseButtons.None, (Keys.P | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationCreateShprossChain()),
                new MouseManagerEvent(MouseButtons.None, (Keys.U |  Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationFixSelectedShprossConnectorAngles()),
                new MouseManagerEvent(MouseButtons.None, (Keys.O | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationSetDistanceBetweenShprossEnds()),
                new MouseManagerEvent(MouseButtons.None, (Keys.L | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationJoinShprossesEnds()),
                new MouseManagerEvent(MouseButtons.None, (Keys.J | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationAutoRotateShprossConnectors()),
                new MouseManagerEvent(MouseButtons.None, (Keys.A | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationMoveComponentsWithOffset(false, OffsetTo.Left)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Left | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationMoveComponentsWithOffset(false, OffsetTo.Right)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Right | Keys.Control)));
            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationMoveComponentsWithOffset(false, OffsetTo.Up)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Up | Keys.Control)));
            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationMoveComponentsWithOffset(false, OffsetTo.Down)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Down | Keys.Control)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationChangeShprossesHeight(ShprossHeightOperation.IncreaseHeight)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Down | Keys.Shift)));

            mouseManager.RegisterCommand(new CommandOperation(this.modelControl, new OperationChangeShprossesHeight(ShprossHeightOperation.DecreaseHeight)),
                new MouseManagerEvent(MouseButtons.None, (Keys.Up | Keys.Shift)));

        }

        private PopupMenuProvider CreatePopupMenus()
        {
            PopupMenuProvider popupProvider = new PopupMenuProvider();
            ModelPopupMenu shprossMenu = new ModelPopupMenu(this.Manipulator);
            ICommand operationCommand = null;

            IOperation alignShprossRelativeToModelHorizontalOperation = new OperationAlignShprossesEndsRelativeToModelHorizontal();
            operationCommand = new CommandOperation(this.modelControl, alignShprossRelativeToModelHorizontalOperation);
            shprossMenu.AddPopupItem("Выравнивание в модели по горизонтали", Resources.ModelHorizontal.ToBitmap(), operationCommand);

            IOperation alignShprossRelativeToModelVerticalOperation = new OperationAlignShprossesEndsRelativeToModelVertical();
            operationCommand = new CommandOperation(this.modelControl, alignShprossRelativeToModelVerticalOperation);
            shprossMenu.AddPopupItem("Выравнивание в модели по вертикали", Resources.ModelVertical.ToBitmap(), operationCommand);

            IOperation alignSelectedShprossesOperation = new OperationAlignSelectedShprosses();
            operationCommand = new CommandOperation(this.modelControl, alignSelectedShprossesOperation);
            shprossMenu.AddPopupItem("Выравнивание концов профилей", null, operationCommand);

            //IOperation sendToBackOperation = new OperationComponentLayoutSendToBack();
            //operationCommand = new CommandOperation(this.modelControl, sendToBackOperation);
            //shprossMenu.AddPopupItem("Переместить назад", Resources.ShprossSendToBack.ToBitmap(), operationCommand);

            IOperation alignSelectedShprossesByAngleOperation = new OperationAlignSelectedShprossesByAngle();
            operationCommand = new CommandOperation(this.modelControl, alignSelectedShprossesByAngleOperation);
            shprossMenu.AddPopupItem("Задать угол для соединённых между собой профилей", Resources.AlignShprossesByAngle.ToBitmap(), operationCommand);

            
            IOperation breakOperation = new OperationBreakSelectedShprossesToPieces();
            operationCommand = new CommandOperation(modelControl, breakOperation);
            shprossMenu.AddPopupItem("Разбить на части", Resources.BreakToPieces, operationCommand);

            IOperation rotateOperation = new OperationRotateComponent();
            operationCommand = new CommandOperation(modelControl, rotateOperation);
            shprossMenu.AddPopupItem("Вращать", Resources.Rotate, operationCommand);

            IOperation rotateShprossRelativeToAxesOperation = new OperationSetShprossesAnglesRelativeToAxes();
            operationCommand = new CommandOperation(modelControl, rotateShprossRelativeToAxesOperation);
            shprossMenu.AddPopupItem("Вращать относительно осей", Resources.ShprossSetAngleBetweenAxes.ToBitmap(), operationCommand);

            IOperation setShprossHorizontal = new OperationAlignSelectedShprossesByAxes(ITAP.ShprossesBuilder.Modelling.Components.Actions.ComponentAlign.Horizontal);
            operationCommand = new CommandOperation(modelControl, setShprossHorizontal);
            shprossMenu.AddPopupItem("Расположить горизонтально", null, operationCommand);

            IOperation setShprossVertical = new OperationAlignSelectedShprossesByAxes(ITAP.ShprossesBuilder.Modelling.Components.Actions.ComponentAlign.Vertical);
            operationCommand = new CommandOperation(modelControl, setShprossVertical);
            shprossMenu.AddPopupItem("Расположить вертикально", null, operationCommand);

            IOperation joinShprossesEndsOperation = new OperationJoinShprossesEnds();
            operationCommand = new CommandOperation(modelControl, joinShprossesEndsOperation);
            shprossMenu.AddPopupItem("Соединить концы профилей", Resources.JoinShprosses.ToBitmap(), operationCommand);


            shprossMenu.AddSeparator();
            IOperation selectStartOperation = new OperationSelectShprossEnds(ShprossPoints.Start);
            operationCommand = new CommandOperation(modelControl, selectStartOperation);
            shprossMenu.AddPopupItem("Выделить начало", Resources.Ball__Green_, operationCommand);

            IOperation selectCenterOperation = new OperationSelectShprossEnds(ShprossPoints.Center);
            operationCommand = new CommandOperation(modelControl, selectCenterOperation);
            shprossMenu.AddPopupItem("Выделить середину", Resources.Ball__Red_, operationCommand);

            IOperation selectEndOperation = new OperationSelectShprossEnds(ShprossPoints.End);
            operationCommand = new CommandOperation(modelControl, selectEndOperation);
            shprossMenu.AddPopupItem("Выделить конец", Resources.Ball__Blue_, operationCommand);
            shprossMenu.AddSeparator();

            IOperation bringToFrontOperation = new OperationComponentLayoutBringToFront();
            operationCommand = new CommandOperation(this.modelControl, bringToFrontOperation);
            shprossMenu.AddPopupItem("Переместить вперёд", Resources.ShprossBringToFront.ToBitmap(), operationCommand);

            IOperation setDistanceBetweenEndsOperation = new OperationSetDistanceBetweenShprossEnds();
            operationCommand = new CommandOperation(modelControl, setDistanceBetweenEndsOperation);
            shprossMenu.AddPopupItem("Задать расстояние между концами арки", Resources.ShprossSetDistanceBetweenEnds.ToBitmap(), operationCommand);

             
            //IOperation removeShprossOperation = new OperationRemoveComponent();
            //operationCommand = new CommandOperation(modelControl, removeShprossOperation);
            //shprossMenu.AddPopupItem("Удалить", null, operationCommand);

            IOperation removeShprossSpacerConnector = new OperationRemoveShprossSpacerConnector();
            operationCommand = new CommandOperation(modelControl, removeShprossSpacerConnector);
            shprossMenu.AddPopupItem("Удалить соединитель в рамку", null, operationCommand);

            IOperation createChainOperation = new OperationCreateShprossChain();
            operationCommand = new CommandOperation(modelControl, createChainOperation);
            shprossMenu.AddPopupItem("Объединить профили", null, operationCommand);

            IOperation createCrossConnectors = new OperationCreateCrossConnectorsOnShprosses();
            operationCommand = new CommandOperation(modelControl, createCrossConnectors);
            shprossMenu.AddPopupItem("Создать пересечение профилей", Resources.ShprossCreateCrossConnector.ToBitmap(), operationCommand);

            IOperation deleteCrossConnectors = new OperationCreateCrossConnectorsOnShprosses();
            operationCommand = new CommandOperation(modelControl, deleteCrossConnectors);
            shprossMenu.AddPopupItem("Удалить пересечение профилей", Resources.ShprossRemoveCrossConnector.ToBitmap(), operationCommand);

            IOperation breakCrossConnectors = new OperationCreateCrossConnectorsOnShprosses();
            operationCommand = new CommandOperation(modelControl, breakCrossConnectors);
            shprossMenu.AddPopupItem("Разбить пересечение профилей", Resources.BreakCrossShprosses.ToBitmap(), operationCommand);



            popupProvider.RegisterPopupMenu(typeof(Shpross), shprossMenu);

            ModelPopupMenu shprossConnectorMenu = new ModelPopupMenu(this.Manipulator);

            IOperation connectorAlignHorizontalOperation = new OperationAlignRelativeToModelHorizontal();
            operationCommand = new CommandOperation(modelControl, connectorAlignHorizontalOperation);
            shprossConnectorMenu.AddPopupItem("Выравнивание в модели по горизонтали", Resources.ModelHorizontal.ToBitmap(), operationCommand);

            IOperation connectorAlignVerticalOperation = new OperationAlignRelativeToModelVertical();
            operationCommand = new CommandOperation(modelControl, connectorAlignVerticalOperation);
            shprossConnectorMenu.AddPopupItem("Выравнивание в модели по вертикали", Resources.ModelVertical.ToBitmap(), operationCommand);

            IOperation alignByConnectorsOperation = new OperationAlignSelectedShprossConnectors();
            operationCommand = new CommandOperation(modelControl, alignByConnectorsOperation);
            shprossConnectorMenu.AddPopupItem("Выравнивание соединителей", null, operationCommand);

            shprossConnectorMenu.AddSeparator();

            IOperation autoRotateConnectorsOperation = new OperationAutoRotateShprossConnectors();
            operationCommand = new CommandOperation(modelControl, autoRotateConnectorsOperation);
            shprossConnectorMenu.AddPopupItem("Автоповорот соединителей", Resources.AutoRotateShprossConnectors.ToBitmap(), operationCommand);

            IOperation stickUnstickHalfSunConnectorToShprossOperation = new OperationStickUnstickHalfSunConnectorToShpross();
            operationCommand = new CommandOperation(modelControl, stickUnstickHalfSunConnectorToShprossOperation);
            shprossConnectorMenu.AddPopupItem("Прикрепить/открепить полусолнышко от профиля", Resources.StickHalfSunConnectorToShpross.ToBitmap(), operationCommand);

            IOperation rotateConnectorsOperation = new OperationRotateShprossConnectors();
            operationCommand = new CommandOperation(modelControl, rotateConnectorsOperation);
            shprossConnectorMenu.AddPopupItem("Вращать соединитель", Resources.RotateShprossConnectors.ToBitmap(), operationCommand);

            

            IOperation addShprossesOperation = new OperationCreateShprossesOnShprossConnector();
            operationCommand = new CommandOperation(modelControl, addShprossesOperation);
            shprossConnectorMenu.AddPopupItem("Надеть профили", Resources.CreateShprossesOnConnectors.ToBitmap(), operationCommand);

            IOperation fixAnglesOperation = new OperationFixSelectedShprossConnectorAngles();
            operationCommand = new CommandOperation(modelControl, fixAnglesOperation);
            shprossConnectorMenu.AddPopupItem("Выровнять соединители", Resources.FixShprossConnectorsAngles.ToBitmap(), operationCommand);

            IOperation removeShprossConnectorSnapOnCapOperation = new OperationRemoveShprossConnectorInnerSnapOnCap();
            operationCommand = new CommandOperation(modelControl, removeShprossConnectorSnapOnCapOperation);
            shprossConnectorMenu.AddPopupItem("Удалить накладку", null, operationCommand);

            //IOperation removeShprossConnectorOperation = new OperationRemoveComponent();
            //operationCommand = new CommandOperation(modelControl, removeShprossConnectorOperation);
            //shprossConnectorMenu.AddPopupItem("Удалить", null, operationCommand);

            popupProvider.RegisterPopupMenu(typeof(ShprossConnector), shprossConnectorMenu);

            ModelPopupMenu snapOnCapMenu = new ModelPopupMenu(this.Manipulator);
            IOperation removeSnapOnCap = new OperationRemoveComponent();
            operationCommand = new CommandOperation(modelControl, removeSnapOnCap);
            snapOnCapMenu.AddPopupItem("Удалить", null, operationCommand);

            popupProvider.RegisterPopupMenu(typeof(SnapOnCap), snapOnCapMenu);

            return popupProvider;
            
        }

        void modelControl_KeyUp(object sender, KeyEventArgs e)
        {
            keyData = Keys.None;            
        }

        private Keys keyData;

        public Keys KeyData
        {
            get { return keyData; }
            set { keyData = value; }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            this.keyData = keyData;

            if(mouseManager.KeyDown(new MouseManagerEvent(MouseButtons.None, this.keyData)))
               this.keyData = Keys.None;

            if (this.keyData == (Keys.Z | Keys.Control))
            {
                this.Manipulator.Undo();
                this.keyData = Keys.None;
            }
            else if (this.keyData == (Keys.Z | Keys.Shift | Keys.Control))
            {
                this.Manipulator.Redo();
                this.keyData = Keys.None;
            }
            return false;
        }

        void modelControl_KeyDown(object sender, KeyEventArgs e)
        {
        }

        void modelControl_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                IModelControlCommand zoomInCommand = new CommandEditorZoomIn(this.ModelControl, "Увеличить", false);
                zoomInCommand.MouseDownPoint = new Point(this.ModelControl.ClientRectangle.Width / 2, this.ModelControl.ClientRectangle.Height / 2);
                this.Manipulator.StartExecute(zoomInCommand);
                this.modelControl.Invalidate();
            }
            else if (e.Delta < 0)
            {
                IModelControlCommand zoomOutCommand = new CommandEditorZoomOut(this.ModelControl, "Увеличить", false);
                zoomOutCommand.MouseDownPoint = new Point(this.ModelControl.ClientRectangle.Width / 2, this.ModelControl.ClientRectangle.Height / 2);
                this.Manipulator.StartExecute(zoomOutCommand);
                this.modelControl.Invalidate();

            }
        }

        //public void UpdateMainControl()
        //{
        //    modelControl.Invalidate();
        //    if (modelControl.ModelContainer != null)
        //        this.RecalculateScrollBars();
        //}

        public void ZoomIn(ModelPoint centerPoint, double scaleDelta)
        {
            modelControl.ZoomIn(centerPoint, scaleDelta);// .Camera = (ModelPoint)centerPoint.Clone();
        }

        public void ZoomOut(ModelPoint centerPoint, double scaleDelta)
        {
            modelControl.ZoomOut(centerPoint, scaleDelta);
        }

        private void RecalculateScrollBars()
        {
            hScrollBarModel.Value = hScrollBarModel.Maximum / 2;
            vScrollBarModel.Value = vScrollBarModel.Maximum / 2;
            return;

            RectangleF fullRectangle = modelControl.FullRectangle;
            RectangleF visibleRectangle = modelControl.VisibleRectangle;

            double widthRatio = fullRectangle.Width / visibleRectangle.Width;
            double heightRatio = fullRectangle.Height / visibleRectangle.Height;
            if (widthRatio <= 1)
            {
                hScrollBarModel.Maximum = 0;
                hScrollBarModel.Value = 0;
                modelControl.Camera = new ModelPoint(modelControl.ModelContainer.BoundingBox.Width / 2, modelControl.ModelContainer.BoundingBox.Height / 2);
            }
            else
            {
                double offsetX = visibleRectangle.X / (fullRectangle.Width - visibleRectangle.Width);
                if (offsetX > 0)
                {
                    hScrollBarModel.Maximum = (int)(5000 * (widthRatio - 1));
                    if ((int)(hScrollBarModel.Maximum * offsetX) < hScrollBarModel.Maximum)
                        hScrollBarModel.Value = (int)(hScrollBarModel.Maximum * offsetX);
                }
            }
            if (heightRatio <= 1)
            {
                vScrollBarModel.Maximum = 0;
                vScrollBarModel.Value = 0;
                modelControl.Camera = new ModelPoint(modelControl.ModelContainer.BoundingBox.Width / 2, modelControl.ModelContainer.BoundingBox.Height / 2);
            }
            else
            {
                double offsetY = visibleRectangle.Y / (fullRectangle.Height - visibleRectangle.Height);
                if (offsetY > 0)
                {
                    vScrollBarModel.Maximum = (int)(5000 * (heightRatio - 1));
                    if ((int)(vScrollBarModel.Maximum * offsetY) < vScrollBarModel.Maximum)
                        vScrollBarModel.Value = (int)(vScrollBarModel.Maximum * offsetY);

                }
            }
        }


        private void vScrollBarModel_Scroll(object sender, ScrollEventArgs e)
        {
            double delta = (double)(e.NewValue - e.OldValue) / (double)vScrollBarModel.Maximum;
            RectangleF bbox = modelControl.ModelContainer.BoundingBox;
            double yOffset = bbox.Height * delta;
            modelControl.Camera = ModelCalculations.GetOffsetPoint(modelControl.Camera, new ModelVector(0, -yOffset));
        }

        private void modelControl_MouseDown(object sender, MouseEventArgs e)
        {
            currentPressedButton = e.Button;
            bool focus = modelControl.Focus();
            mouseManager.MouseDown(e.Location, new MouseManagerEvent(e.Button, this.keyData));
            modelControl.MouseKeyCombination = e.Button.ToString() + " + " + keyData.ToString();
            modelControl.Invalidate();
        }

        private void modelControl_MouseUp(object sender, MouseEventArgs e)
        {
            currentPressedButton = e.Button;
            mouseManager.MouseUp(e.Location, new MouseManagerEvent(e.Button, this.keyData));
            modelControl.MouseKeyCombination = "";
            modelControl.Invalidate();
        }

        public MoveDirection GetMoveDirection()
        {
            return this.mouseManager.MoveDirection;
        }


        private void modelControl_MouseMove(object sender, MouseEventArgs e)
        {            
            if (this.mouseManager.MoveDirection == MoveDirection.Both)
            {
                if (this.keyData == Keys.Q)
                {
                    this.mouseManager.MoveDirection = MoveDirection.Vertical;
                    currentPressedButton = e.Button;
                    mouseManager.MouseMove(e.Location, new MouseManagerEvent(e.Button, this.keyData));
                    this.mouseManager.MoveDirection = MoveDirection.Both;
                }
                else if (this.keyData == Keys.W)
                {
                    this.mouseManager.MoveDirection = MoveDirection.Horizontal;
                    currentPressedButton = e.Button;
                    mouseManager.MouseMove(e.Location, new MouseManagerEvent(e.Button, this.keyData));
                    this.mouseManager.MoveDirection = MoveDirection.Both;
                }
                else
                {
                    currentPressedButton = e.Button;
                    mouseManager.MouseMove(e.Location, new MouseManagerEvent(e.Button, this.keyData));
                }

            }
            else
            {
                currentPressedButton = e.Button;
                mouseManager.MouseMove(e.Location, new MouseManagerEvent(e.Button, this.keyData));
            }
        }

        private void modelControl_Paint(object sender, PaintEventArgs e)
        {
        }

        private void modelControl_DragEnter(object sender, DragEventArgs e)
        {

        }

        private void modelControl_DragDrop(object sender, DragEventArgs e)
        {

        }

        private void modelControl_MouseEnter(object sender, EventArgs e)
        {
         //   bool focus = modelControl.Focus();
        }

        private void modelControl_DragOver(object sender, DragEventArgs e)
        {

        }

        //public void UpdateVisitors()
        //{
        //    foreach (IModelVisitor visitor in this.visitors)
        //        visitor.Visit(modelControl.ModelContainer);
        //}
    }
}
